package com.speechb.modules.system.admin.controller.base;


import com.alibaba.fastjson.JSONObject;
import com.speechb.common.GZipUtils;
import com.speechb.common.MD5Util;
import com.speechb.common.text.TextUtil;
import com.speechb.modules.system.entity.ConstantParas;
import com.speechb.modules.system.entity.DataPager;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.Writer;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author llj
 * @date 2019-8-4
 */
public class BaseController {
    private static final Logger logger = LoggerFactory.getLogger(BaseController.class);
    private static final String JSON_DATA_MAP = "json_data_map";

    /*不能这样使用，会出现线程安全问题, 单列模式变量共享导致数据中断*/
/*	protected HttpServletRequest request;
	protected HttpServletResponse response;
	protected HttpSession session;*/
    /**
     * 说明：ModelAttribute的作用<br/>
     * 1)放置在方法的形参上：表示引用Model中的数据<br/>
     * 2)放置在方法上面：表示请求该类的每个Action前都会首先执行它，也可以将一些准备数据的操作放置在该方法里面。<br/>
     *
     * 此方法用于给request和response赋值
     */
/*	@ModelAttribute
 final	public void setReqAndRes(HttpServletRequest request,
			HttpServletResponse response) {
*//*		this.request = request;
		this.response = response;
		this.session = request.getSession();*//*
		Local.put("HttpServletRequest",request);
		Local.put("HttpServletResponse",response);
		Local.put("HttpSession",request.getSession());
	}*/
/*	@InitBinder
	protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
		DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		CustomDateEditor dateEditor = new CustomDateEditor(format, true);
		binder.registerCustomEditor(Date.class, dateEditor);

	}*/

/*  protected HttpServletRequest getRequest(){
	  return (HttpServletRequest) Local.get("HttpServletRequest");
  }*/

    /**
     * RequestContextHolder.getRequestAttributes在大部分的情况下，<br/>
     * 它都能很好地工作，但在商品管理编辑中，新增商品时，却出现了意外的问题：
     * 通过RequestHolder.getRequest().getParameter()得不到参数值，
     * 通过warn发现，通过spring mvc的method注入的request对象实际
     * 为MultipartHttpServletRequest,而通过RequestHolder.getRequest()获取到的
     * request对象却是RequestFacfade的实例。
     * 原来在商品新增时，由于使用了文件上传，form表单的enctype类型为
     * ”multipart/form-data”，spring mvc对文件上传的处理类实际
     * 却为spring-mvc.xml文件中配置的CommonsMultipartResolver，
     * 该类先判断当前请求是否为multipart类型，如果是的话，
     * 将request对象转为MultipartHttpServletRequet,
     * 相关的源码见DisptcherServlet
     * <p>
     * 解决：<br/>
     * HttpServletRequest作为spring mvc的方法入参<br/>
     * 本解决方案为将request对象通过拦截器放入当前当前线程Map中，然后获取
     *
     * @return
     */
    protected HttpServletRequest getRequest() {
        //不能直接放在ThreadMap中。用户多个请求可能在一个线程
	/*	HttpServletRequest request= (HttpServletRequest) Local.getExtraCurrentThreadMap().get("HttpServletRequest");
    	if(request!=null){
    		return request;

		}*/
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        return ((ServletRequestAttributes) ra).getRequest();
    }

    protected HttpServletResponse getResponse() {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        return ((ServletRequestAttributes) ra).getResponse();
    }

    protected HttpSession getSession() {
        return getRequest().getSession();
    }

    /**
     * 存放数据到request域中名为json_data_map的HashMap集合
     *
     * @param key
     * @param value
     */
    protected void setAttr(String key, Object value) {
        if (Objects.nonNull(key)&&Objects.nonNull(value)) {
            getDataMap().put(key, value);
        }
    }
    protected void setData(Object value){
        if(value != null) {
            setAttr(ConstantParas.JSON_DATA, value);
        }
    }

    /**
     * 设置状态码
     */
    protected void setStatus(int code) {
        getResponse().setStatus(code);
    }
    protected void setDataAndRender(Object value){
        setAttr(ConstantParas.JSON_DATA, value);
        render();
    }

    protected Map getDataMap() {
        Map<String, Object> jsonDataMap = (Map<String, Object>) getRequest().getAttribute(
                JSON_DATA_MAP);
        if (jsonDataMap == null) {
            synchronized (this) {
                if (jsonDataMap == null) {
                    jsonDataMap = new ConcurrentHashMap<>(16);
                    getRequest().setAttribute(JSON_DATA_MAP, jsonDataMap);
                }
            }
        }
        return jsonDataMap;
    }

    /**
     * 从要返回给用户的map中获取数据
     * @param key
     */
    protected void getAttr(String key) {
        getDataMap().get(key);
    }

    /**
     * 从request域拿数据
     * @param key
     * @return
     */
    protected String getPara(String key) {
        return getRequest().getParameter(key);
    }
    /**
     * 从request域拿数据
     * @param key
     * @return
     */
    protected String[] getParas(String key) {
        return getRequest().getParameterValues(key);
    }
    /**
     * 从Request域中获取Int值,传入的Key为空时，默认为零
     *
     * @return
     */
    protected Integer getInt(String key) {
        return Integer.parseInt(getPara(key, "0"));
    }

    /**
     * 从Request域中获取Int值,传入的Key为空时，默认为零
     *
     * @return
     */
    protected Integer getInt(String key, int def) {
        return Integer.parseInt(getPara(key, String.valueOf(def) ));
    }

    protected Boolean getBoolean(String key, Boolean def) {
        String value = getPara(key);
        if (StringUtils.isEmpty(value)) {
            return def;
        }
        return Boolean.parseBoolean(value);
    }

    protected Boolean getBoolean(String key) {
        return Boolean.parseBoolean(getPara(key));
    }

    protected String getPara(String key, String def) {
        String value = getRequest().getParameter(key);
        if (StringUtils.isEmpty(value)) {
            value = def;
        }
        return value;
    }

    /**
     * 获得用户手机唯一标识
     */
    protected String getPhoneSign() {
        return (String) getSession().getAttribute(ConstantParas.PHONE_SING);
    }

    /**
     * 设置用户手机唯一标识
     */
    protected void setPhoneSign(String phoneSign) {
        getSession().setAttribute(ConstantParas.PHONE_SING, phoneSign);
    }

    /**
     * 从request中获得key为page_num的值，当其为空时默认为零
     *
     * @return int
     */
    protected int getPageNum() {
        return Integer.parseInt(getPara("page_num", "1"));
    }

    /**
     * 从request中获得key为page_size的值，当其为空时默认为零
     *
     * @return int
     */
    protected int getPageSize() {
        /*Integer.parseInt(getPara("page_size","0"))*/
        ;
        return 10;
    }

    /**
     * 渲染成功， 并把code设为1，message设为操作成功
     * 渲染json格式
     * {
     * code:1
     *   msg:"success"
     * data{
     * data:{
     *    }
     *   }
     * }
     * render
     */
    @Deprecated
    protected void renderSuccess() {
        Map<String, Object> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, ConstantParas.CODE_SUCCESS);
        map.put(ConstantParas.JSON_MESSAGE, ConstantParas.MESSAGE_SUCCESS);
        renderJson();
    }

    /**
     * 推荐使用
     * 渲染json格式
     * {
     *     code:1
     *     msg:"success"
     *     data:{
     *
     *     }
     *
     * }
     */
    protected void render() {
        Map<String, Object> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, ConstantParas.CODE_SUCCESS);
        map.put(ConstantParas.JSON_MESSAGE, ConstantParas.MESSAGE_SUCCESS);
        renderJson1(true);
    }
    protected void renderUnCompressSuccess() {
        Map<String, Object> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, ConstantParas.CODE_SUCCESS);
        map.put(ConstantParas.JSON_MESSAGE, ConstantParas.MESSAGE_SUCCESS);
        renderJson1(false);
    }

    protected void renderNoStatus() {
        renderJson1(true);
    }
    /**
     * 只是渲染数据成Json，不格式化json数据
     */
    protected void renderJsonStr() {
        HttpServletResponse response = getResponse();
        response.setContentType("text/html;charset=utf-8");
        try {
            Writer writer = response.getWriter();
            Map map = getDataMap();
            String mapStr = JSONObject.toJSONString(map);
            logger.warn("Return json is:{}",mapStr);
            map.clear();
            writer.write(mapStr);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    protected <T> void writeData(List<T> t, int total) {
        HttpServletResponse response = getResponse();
        response.setContentType("text/html;charset=utf-8");
        DataPager<T> dataPager = new DataPager<>();
        try {
            dataPager.setRows(t);
            dataPager.setTotal(total);
            Writer writer = response.getWriter();
            String mapStr = JSONObject.toJSONString(dataPager);
            logger.debug("Return json is:{}",mapStr);
            writer.write(mapStr);
        } catch (IOException e) {
            logger.error("IOException",e);
        }
    }
    /**
     * 渲染失败， 并把code设为0，message设为操作失败
     */
    protected void renderFail() {
        renderFail(ConstantParas.MESSAGE_FIAL);
    }

    /**
     * 渲染失败，并设置提示内容
     *
     * @param errMsg 错误信息
     */
    protected void renderFail(String errMsg) {
        Map<String, Object> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, ConstantParas.CODE_FAIL);
        map.put(ConstantParas.JSON_MESSAGE, errMsg);
        renderJson();
    }
    protected void renderJsonCompress() {
        renderJson(true);
    }

    protected void renderJsonUnCompress() {
        renderJson(false);
    }

    protected void renderJson() {
        renderJson(true);
    }
    protected void renderJson1(boolean compress) {
        HttpServletResponse response = getResponse();
        response.setContentType("application/json;charset=utf-8");
        try {
            Map map = getDataMap();
            String mapStr = JSONObject.toJSONString(map);
            if (md5Matcher(response, mapStr)) {
                return;
            }
            logger.debug("Return json is:{}", mapStr);
            if (compress  && mapStr.length() > 100) {
                response.setHeader("gzip", "true");
                response.getOutputStream().write(GZipUtils.compress(mapStr));
            } else {
                Writer writer = response.getWriter();
                writer.write(mapStr);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            logger.error("Json conversion failed",e);
        }
    }
    /**
     *
     *
     * @param compress 是否压缩
     */
    protected void renderJson(boolean compress) {
        HttpServletResponse response = getResponse();
        response.setContentType("application/json;charset=utf-8");
        try {
            Map map = getDataMap();

            String mapStr = JSONObject.toJSONString(formatMap2Json(map));
            if (md5Matcher(response, mapStr)) {
                return;
            }
            map.clear();
            logger.debug("Return json is:{}", mapStr);
            if (compress  && mapStr.length() > 100) {
                response.setHeader("gzip", "true");
                response.getOutputStream().write(GZipUtils.compress(mapStr));
            } else {
                Writer writer = response.getWriter();
                writer.write(mapStr);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private boolean md5Matcher(HttpServletResponse response, String mapStr) throws IOException {
        String md5ContentCode = getRequest().getHeader("md5_content_code");
        if(StringUtils.isNotEmpty(md5ContentCode)) {
            // MD5一致不用更新
            String md5String = MD5Util.getMD5String(mapStr);
            logger.warn("md5吗："+md5ContentCode + "  " +md5String);
            if(StringUtils.equals(md5ContentCode,md5String)) {
                Writer writer = response.getWriter();
                logger.warn("Return json is:{}", "{\"message\":\"数据一致\",\"code\":1}");
                writer.write("{\"message\":\"数据一致\",\"code\":1}");
                return true;
            } else {
                response.addHeader("data_change","true");
            }
        }
        return false;
    }

    protected Map formatMap2Json(Map<String, Object> map) {
        Map<String, Object> jsonMap = new HashMap<String, Object>();
        Map<String, Object> dataMap = new HashMap<String, Object>();
        Set<Entry<String, Object>> set = map.entrySet();

        for (Entry<String, Object> entry : set) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (ConstantParas.JSON_CODE.equals(key)) {
                jsonMap.put(ConstantParas.JSON_CODE, value);
            } else if (ConstantParas.JSON_MESSAGE.equals(key)) {
                jsonMap.put(ConstantParas.JSON_MESSAGE, value);
            } else {
                dataMap.put(key, value);
            }
        }
        if (TextUtil.isEmpty(map.get(ConstantParas.JSON_CODE))) {
            jsonMap.put(ConstantParas.JSON_CODE, ConstantParas.CODE_SUCCESS);
        }
        if (map.get(ConstantParas.JSON_MESSAGE) == null || map.get(ConstantParas.JSON_MESSAGE) == "") {
            jsonMap.put(ConstantParas.JSON_MESSAGE, ConstantParas.MESSAGE_SUCCESS);
        }


        if (!dataMap.isEmpty()) {
            jsonMap.put(ConstantParas.JSON_DATA, dataMap);
        }
        return jsonMap;
    }

    protected void renderUserNoExist() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-1");
        map.put(ConstantParas.JSON_MESSAGE, "此用户不存在");
        renderJson();
    }

    protected void renderPasswordNoMatch() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-2");
        map.put(ConstantParas.JSON_MESSAGE, "密码有误");
        renderJson();
    }

    protected void renderAuthCodeNoMath() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-3");
        map.put(ConstantParas.JSON_MESSAGE, "验证码有误");
        renderJson();
    }

    protected void renderParasLose() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-4");
        map.put(ConstantParas.JSON_MESSAGE, "参数丢失");
        renderJson();
    }

    protected void renderParasMispatch() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-5");
        map.put(ConstantParas.JSON_MESSAGE, "参数格式不匹配");
        renderJson();
    }

    protected void renderUserExist() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-6");
        map.put(ConstantParas.JSON_MESSAGE, "用户已经存在");
        renderJson();
    }

    protected void renderDBError() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-7");
        map.put(ConstantParas.JSON_MESSAGE, "数据库操作失败");
        renderJson();
    }

    protected void renderSaveFileError() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-8");
        map.put(ConstantParas.JSON_MESSAGE, "文件保存失败");
        renderJson();
    }

    protected void renderExist() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-9");
        map.put(ConstantParas.JSON_MESSAGE, "已经存在");
        renderJson();
    }

    protected void renderNoLogin() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-10");
        map.put(ConstantParas.JSON_MESSAGE, "用户未登录");
        renderJson();
    }

    protected void renderHadCheckIn() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-11");
        map.put(ConstantParas.JSON_MESSAGE, "今天已经签到");
        renderJson();
    }

    protected void renderAutoLoginFail() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-12");
        map.put(ConstantParas.JSON_MESSAGE, "自动登录失效");
        renderJson();
    }
    protected void renderCaptchaNoMatch() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-13");
        map.put(ConstantParas.JSON_MESSAGE, "验证码错误");
        renderNoStatus();
    }
    protected void renderRepeatBuy() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-14");
        map.put(ConstantParas.JSON_MESSAGE, "重复购买");
        renderNoStatus();
    }
    protected void renderBuyFail() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-15");
        map.put(ConstantParas.JSON_MESSAGE, "购买失败");
        renderNoStatus();
    }
    protected void renderNotSufficientFunds() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-16");
        map.put(ConstantParas.JSON_MESSAGE, "余额不足");
        renderNoStatus();
    }
    protected void renderNotExist() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-17");
        map.put(ConstantParas.JSON_MESSAGE, "资源已经删除");
        renderNoStatus();
    }
    protected void renderTimesOut() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-18");
        map.put(ConstantParas.JSON_MESSAGE, "本月次数已经用完");
        renderNoStatus();
    }
    protected void renderActivationCodeFail() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-19");
        map.put(ConstantParas.JSON_MESSAGE, "激活码无效");
        renderNoStatus();
    }
    protected void renderContentRepeat() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-20");
        map.put(ConstantParas.JSON_MESSAGE, "内容重复");
        renderNoStatus();
    }
    protected void renderUsedCode() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-21");
        map.put(ConstantParas.JSON_MESSAGE, "激活码已经使用或无效");
        renderNoStatus();
    }

    protected void renderNoPermission() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-22");
        map.put(ConstantParas.JSON_MESSAGE, "权限拒绝");
        renderNoStatus();
    }

    protected void renderRepeatVip() {
        Map<String, String> map = getDataMap();
        map.put(ConstantParas.JSON_CODE, "-23");
        map.put(ConstantParas.JSON_MESSAGE, "已经激活VIP");
        renderNoStatus();
    }

    protected String getRootPath() {
        return System.getProperty("webapp_root_path");
    }

    protected boolean isAjaxRequest() {
        String requestedWith = getRequest().getHeader("X-Requested-With");
        if (getRequest().getHeader("x-requested-with") != null
                && getRequest().getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")) {
            return true;
        }else{
            return false;
        }
    }
    protected String render404Page() {
        setStatus(404);
        return "web/app/error/404";
    }
    protected String render500Page() {
        setStatus(500);
        return "web/app/error/500";
    }


}
